/*
 *  Copyright (C) 2011 glauco
 * 
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 * 
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 * 
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.balisunrise.swing.builders;

import javax.swing.JPanel;
import org.balisunrise.annotation.EventType;
import org.balisunrise.annotation.util.AnnotationsUtilitiesException;
import org.balisunrise.annotation.util.NameUtil;
import org.balisunrise.annotation.util.TransactionUtilities;
import org.balisunrise.application.Application;
import org.balisunrise.builder.BuilderException;
import org.balisunrise.common.Action;
import org.balisunrise.common.ActionProvider;
import org.balisunrise.common.Editor;
import org.balisunrise.common.EntityActions;
import org.balisunrise.common.Mode;
import org.balisunrise.common.Search;
import org.balisunrise.common.Transaction;
import org.balisunrise.common.TransactionActions;
import org.balisunrise.common.VisualAction;
import org.balisunrise.swing.commons.listeners.TransactionListener;
import org.balisunrise.swing.components.panel.TransactionPanel;
import org.balisunrise.swing.components.panel.layouts.TransactionLayoutBuilder;

/**
 *
 * @author glauco
 */
public class TransactionBuilder
    implements org.balisunrise.builder.TransactionBuilder{

    private static final String MESSAGE = "Erro ao construir uma Transaction.\n";

    @Override
    public Transaction create(Class entityClass, String alias)
            throws BuilderException {

        if(entityClass == null){
            throw new BuilderException(MESSAGE +
                    "entityClass não pode ser nulo.");
        }

        if(alias == null){
            throw new BuilderException(MESSAGE +
                    "alias não pode ser nulo.");
        }

        try {
            TransactionUtilities tu =
                    TransactionUtilities.create(entityClass, alias);
            return create(tu);
        } catch (AnnotationsUtilitiesException ex) {
            throw new BuilderException(MESSAGE +
                    ex.getMessage(), ex);
        }
    }

    @Override
    public Transaction create(TransactionUtilities tu) throws BuilderException {

        if(tu == null){
            throw new BuilderException(MESSAGE +
                    "transactionUtilities não pode ser nulo.");
        }

        // cria transaction
        org.balisunrise.swing.commons.Transaction t =
                new org.balisunrise.swing.commons.Transaction();

        // atribuições
        t.setAlias(tu.alias);
        t.setEntityClass(tu.entityClass);
        t.setTitle(tu.title);

        // Constrói a Busca
        Search<?,?,?,JPanel> search = Application.get()
                .getVisualEntityManager()
                .getSearchBuilder()
                .create(tu.searchUtilities);

        // Constrói o Editor
        Editor<?,?,?,JPanel> editor = Application.get()
                .getVisualEntityManager()
                .getEditorBuilder()
                .create(tu.editorUtilities);

        // Constrói as ações
        TransactionActions<org.balisunrise.swing.commons.Transaction,
                VisualAction,JPanel> ta = Application.get()
                .getVisualEntityManager()
                .getTransactionActionBuilder()
                .create(tu.entityClass,
                        tu.alias);

        // atribui a transaction das ações
        ta.setTransaction(t);

        // método de criação
        ta.setCreateMethod(tu.createMethod);

        // atribui owner
        search.setOwner(t);
        editor.setOwner(t);
        ta.setOwner(t);

        // cria ações de confirmação e cancelamento
        String empty = "";
        VisualAction confirmationAction1 = Application.get()
                .getVisualEntityManager()
                .getActionBuilder()
                .createConfirmationAction(ta, empty);
        VisualAction cancellationAction1 = Application.get()
                .getVisualEntityManager()
                .getActionBuilder()
                .createCancellationAction(ta, empty);
        VisualAction confirmationAction2 = Application.get()
                .getVisualEntityManager()
                .getActionBuilder()
                .createConfirmationAction(ta, empty);
        VisualAction cancellationAction2 = Application.get()
                .getVisualEntityManager()
                .getActionBuilder()
                .createCancellationAction(ta, empty);

        // atribui as ações de confirmação e cancelamento
        EntityActions editorAction = editor.getEntityActions();
        confirmationAction1.setOwner(editorAction);
        cancellationAction1.setOwner(editorAction);
        editorAction.setConfirmationAction(confirmationAction1);
        editorAction.setCancellationAction(cancellationAction1);
        // atribui as ações de confirmação e cancelamento
        EntityActions searchAction = search.getEntityActions();
        confirmationAction2.setOwner(searchAction);
        cancellationAction2.setOwner(searchAction);
        searchAction.setConfirmationAction(confirmationAction2);
        searchAction.setCancellationAction(cancellationAction2);

        // provedor de ações
        ActionProvider ap = Application.get().getActionMapManager()
                .getActionProvider(tu.entityClass);

        // cria listener da transaction
        TransactionListener tl = new TransactionListener();
        t.addTransactionListener(tl);

        // ações de eventos de antes de validar
        Action[] as = ap.getActions(EventType.TRANSACTION_BEFORE_VALIDATE,
                tu.alias, null);
        for (Action action : as) {
            action.setOwner(t);
            tl.addBeforeValidadeAction(action);
        }

        // ações de eventos de antes de salvar
        as = ap.getActions(EventType.TRANSACTION_BEFORE_SAVE, tu.alias, null);
        for (Action action : as) {
            action.setOwner(t);
            tl.addBeforeSaveAction(action);
        }

        // ações de eventos de depois de salvar
        as = ap.getActions(EventType.TRANSACTION_AFTER_SAVE, tu.alias, null);
        for (Action action : as) {
            action.setOwner(t);
            tl.addAfterSaveAction(action);
        }

        // ações de eventos de antes de deletar
        as = ap.getActions(EventType.TRANSACTION_BEFORE_DELETE, tu.alias, null);
        for (Action action : as) {
            action.setOwner(t);
            tl.addBeforeDeleteAction(action);
        }

        // ações de eventos de depois de deletar
        as = ap.getActions(EventType.TRANSACTION_AFTER_DELETE, tu.alias, null);
        for (Action action : as) {
            action.setOwner(t);
            tl.addAfterDeleteAction(action);
        }

        // cria representação visual
        TransactionPanel vr = new TransactionPanel(
                ta.getVisualRepresentation(),
                editor.getVisualRepresentation(),
                search.getVisualRepresentation(),
                new TransactionLayoutBuilder());

        // atribuições
        t.setEditor(editor);
        t.setSearch(search);
        t.setTransactionActions(ta);
        t.setVisualRepresentation(vr);

        // nome da transaction
        String name = NameUtil.buildName(ta);
        t.getVisualRepresentation().setName(name);
        t.getVisualRepresentation().getAccessibleContext().setAccessibleName(name);
        t.setName(name);

        t.setMode(Mode.SEARCH);

        return t;
    }
}
